﻿using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;

namespace Black.NBT
{
    /// <summary>
    /// Représente un Tag de manière générale
    /// </summary>
    public abstract class Tag : IComparable<Tag>, INotifyPropertyChanged
    {
        #region Evénéments

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Propriétés

        /// <summary>
        /// Obtient ou définit le nom du tag
        /// </summary>
        public string Name
        {
            get
            {
                return (this._name);
            }
            set
            {
                if ( this._name != value)
                {
                    this._name = value;
                    this.OnPropertyChanged();
                }
            }
        }

        /// <summary>
        /// Obtient le type du tag
        /// </summary>
        public TagType TagType
        {
            get;
            protected set;
        }

        #endregion

        #region Variables d'instances

        private string _name;

        #endregion

        #region Constructeurs

        /// <summary>
        /// Constructeur de la classe
        /// </summary>
        /// <param name="name">Nom du tag</param>
        public Tag(string name)
        {
            this.Name = name;
            this.TagType = NBT.TagType.Unknown;
        }

        #endregion

        #region Fonctions publiques

        /// <summary>
        /// Compare deux instances
        /// </summary>
        /// <param name="other">Instance de comparaison</param>
        /// <returns>Indicateur de comparaison</returns>
        public int CompareTo(Tag other)
        {
            return (this.TagType.CompareTo(other.TagType));
        }

        #endregion

        #region Fonctions internes

        /// <summary>
        /// Ecrit le tag dans le stream
        /// </summary>
        /// <param name="stream">Instance du flux</param>
        internal void WriteToStream(MemoryStream stream)
        {
            this.WriteToStream(stream, false);
        }

        /// <summary>
        /// Ecrit le tag dans le stream
        /// </summary>
        /// <param name="stream">Instance du flux</param>
        /// <param name="writeName">Inscrit le nom dans le flux</param>
        internal virtual void WriteToStream(MemoryStream stream, bool writeName)
        {
        }

        #endregion

        #region Fonctions protégées

        /// <summary>
        /// Notifie le changement d'une propriété
        /// </summary>
        /// <param name="name">Nom de la propriété</param>
        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        #endregion

        #region Fonctions statiques

        /// <summary>
        /// Récupère le nom du tag
        /// </summary>
        /// <param name="stream">Instance du flux</param>
        /// <returns>Nom du tag</returns>
        public static string ReadName(MemoryStream stream)
        {
            return (NBTFile.ReadString(stream));
        }

        #endregion
    }
}
